#include <jni.h>
#include "utils.h"

JNIEXPORT jobject JNICALL
Java_com_yochi_pictureseditor_effects_effectsimpl_EffectSepia_process(JNIEnv* env, jobject this, jobject imageObject) {


	/* ------ Parse entries ------ */

	// get entry image
	jclass imageimplClass = 		(*env)->GetObjectClass(env, imageObject);


	/* ------ Parse entries ------ */

	// image constructor methods
	jmethodID midConstructor = 		(*env)->GetMethodID(env, imageimplClass, "<init>", 			"(III)V");

	// image getter methods
	jmethodID midGetHauteur = 		(*env)->GetMethodID(env, imageimplClass, "getHauteur", 		"()I");
	jmethodID midGetLargeur = 		(*env)->GetMethodID(env, imageimplClass, "getLargeur", 		"()I");
    jmethodID midGetProfondeur = 	(*env)->GetMethodID(env, imageimplClass, "getProfondeur", 	"()I");
    jmethodID midGetPixel = 		(*env)->GetMethodID(env, imageimplClass, "getPixel", 		"(III)C");
    jmethodID midGetAveragePixel = 	(*env)->GetMethodID(env, imageimplClass, "getAveragePixel", "(II)C");

    // image setter methods
    jmethodID midSetPixel = 		(*env)->GetMethodID(env, imageimplClass, "setPixel", 		"(IIIC)V");


    /* ------ Recover attributes ------ */

    // get image parameters
    int hauteur = 					(*env)->CallIntMethod(env, imageObject, midGetHauteur);
    int largeur = 					(*env)->CallIntMethod(env, imageObject, midGetLargeur);
    int profondeur = 				(*env)->CallIntMethod(env, imageObject, midGetProfondeur);


    /* ------ Instantiate result image ------ */

    jobject imageResult = 			(*env)->NewObject(env, imageimplClass, midConstructor, 4, largeur, hauteur);

    /* ------ Process effect ------ */

    int l, h;
    char r1, g1, b1, a1;
    char r2, g2, b2;

	for(l=0; l<largeur; l++) {

		for(h=0; h<hauteur; h++) {

			if(profondeur == 4) {
				// get pixel values
				r1 = 	(*env)->CallIntMethod(env, imageObject, midGetPixel, 0, l, h);
				g1 = 	(*env)->CallIntMethod(env, imageObject, midGetPixel, 1, l, h);
				b1 = 	(*env)->CallIntMethod(env, imageObject, midGetPixel, 2, l, h);
				a1 =	(*env)->CallIntMethod(env, imageObject, midGetPixel, 3, l, h);
				// compute new pixel values
				r2 = 	(char) troncate( 	((double) r1)*0.393	+ 	((double) g1)*0.769	+ 	((double) b1)*0.189	);
				g2 = 	(char) troncate( 	((double) r1)*0.343	+ 	((double) g1)*0.686	+ 	((double) b1)*0.168	);
				b2 = 	(char) troncate( 	((double) r1)*0.272	+ 	((double) g1)*0.534	+ 	((double) b1)*0.131	);

			} else {
				// get pixel values
				r1 = 	(*env)->CallIntMethod(env, imageObject, midGetPixel, 0, l, h);
				a1 =	(*env)->CallIntMethod(env, imageObject, midGetPixel, 1, l, h);
				// compute new pixel values
				r2 = 	(char) troncate( 	((double) r1)*0.393	+ 	((double) r1)*0.769	+ 	((double) r1)*0.189	);
				g2 = 	(char) troncate( 	((double) r1)*0.343	+ 	((double) r1)*0.686	+ 	((double) r1)*0.168	);
				b2 = 	(char) troncate( 	((double) r1)*0.272	+ 	((double) r1)*0.534	+ 	((double) r1)*0.131	);
			}

			// set result pixel values
			(*env)->CallVoidMethod(env, imageResult, midSetPixel, 0, l, h, r2);
			(*env)->CallVoidMethod(env, imageResult, midSetPixel, 1, l, h, g2);
			(*env)->CallVoidMethod(env, imageResult, midSetPixel, 2, l, h, b2);
			(*env)->CallVoidMethod(env, imageResult, midSetPixel, 3, l, h, a1);

		}
	}

    return imageResult;
}
